package ar.com.guess.image;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.LinkedList;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.gesture.Gesture;
import android.gesture.GestureLibraries;
import android.gesture.GestureLibrary;
import android.gesture.GestureOverlayView;
import android.gesture.Prediction;
import android.gesture.GestureOverlayView.OnGesturePerformedListener;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Animation.AnimationListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.RelativeLayout.LayoutParams;
import ar.com.guess.image.entities.Image;
import ar.com.guess.image.enums.Constant;
import ar.com.guess.image.enums.LanguagePlay;
import ar.com.guess.image.enums.Level;
import ar.com.guess.image.enums.TypeUse;
import ar.com.guess.image.utils.ImageBuilder;
import ar.com.guess.image.utils.MovieBuilder;

public class InitActivity extends Activity implements OnGesturePerformedListener{

	private Level level = Level.ONE;
	private LanguagePlay language = LanguagePlay.ES;
	private TypeUse typeUse = TypeUse.KEYWORD;
	
	/** Puntaje acumulado*/
	private Long score;
	
	/**Imagenes a adivinar por level y lenguaje*/
	private LinkedList<Image> imagesGuess;
	
	/**Imagen actual que se esta adivinando*/
	private Image actualImageGuess;
	
	/** Builder que contruye imagenes de peliculas */
	private ImageBuilder movieBuilder = new MovieBuilder();
	
	/**Numero de la imagen que se esta adivinando*/
	private Integer numberImageToGuess=0;
	
	/**Numero de intentos para adivinar*/
	private Integer numberOfIntent=0;
	
	/**Numero de letras adivinadas*/
	private Integer numberOfLetterGuess=0;
	
	/**Numero de imagenes adivinadas*/
	private Integer imagesWereGuess=0;
	
    private GestureLibrary mLibrary;

	
    private void chargeParameters(){
    	
    	SharedPreferences settings = getSharedPreferences(Constant.DATA_SHARE.name(), MODE_PRIVATE);
    	String typeParam = settings.getString(Constant.PARAM_USE_TYPE.getValue(), TypeUse.GESTURE.name());
    	String langParam = settings.getString(Constant.PARAM_LANGUAGE.getValue(), LanguagePlay.ES.name());
    	String levelParam = settings.getString(Constant.PARAM_LEVEL.getValue(),Level.ONE.getNum());
    	this.score = settings.getLong(Constant.SCORE.getValue(), 0L);
    	this.typeUse = TypeUse.valueOf(typeParam);
    	this.language = LanguagePlay.valueOf(langParam);
    	this.level = Level.getLevel(levelParam);
    }
    
    private void saveParameters(){
    	SharedPreferences settings = getSharedPreferences(Constant.DATA_SHARE.name(), MODE_PRIVATE);
    	Editor editor = settings.edit();
    	editor.putString(Constant.PARAM_LEVEL.getValue(), this.level.getNum());
    	editor.putLong(Constant.SCORE.getValue(),this.score);
    	editor.commit();
    }
    
    public void checkIfANewGame(){
    	boolean isANewGame = super.getIntent().getExtras().getBoolean(Constant.NEW_GAME.getValue());
    	if (isANewGame){
    		String[] levelFiles = super.fileList();
    		for (String nameLevel : levelFiles) {
				super.deleteFile(nameLevel);
			}
    		this.score = 0L;
    		SharedPreferences settings = getSharedPreferences(Constant.DATA_SHARE.name(), MODE_PRIVATE);
    		Editor editor = settings.edit();
        	editor.putLong(Constant.SCORE.getValue(),this.score);
        	editor.putString(Constant.PARAM_LEVEL.getValue(),Level.ONE.getNum());
        	editor.commit();
    	}
    }
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
    	this.checkIfANewGame();
        super.onCreate(savedInstanceState);
        this.chargeParameters();
        if (TypeUse.GESTURE.equals(typeUse)){
        	setContentView(R.layout.main_gesture);
        } else{
        	setContentView(R.layout.main_keyword);
        }
        this.loadImages();
        if (this.imagesGuess == null){
        	this.imagesGuess= this.movieBuilder.createImagesByLevel(level, language, super.getResources(),super.getPackageName());
        	this.saveImages();
        }
        this.drawImage();
        if  (TypeUse.GESTURE.equals(typeUse)){
        	mLibrary = GestureLibraries.fromRawResource(this, R.raw.letters);
        	if (!mLibrary.load()) {
        		finish();
        	}
        	GestureOverlayView gestures = (GestureOverlayView) findViewById(R.id.gestures);
        	gestures.addOnGesturePerformedListener(this);
        }
        
    }
    
    private void showLevel() {
    	TextView textLevel = (TextView)super.findViewById(R.id.numLevelToPlay);
        textLevel.setText(this.level.getNum());		
	}

	private void saveImages(){
    	OutputStream fos = null;
    	OutputStream buffer = null;
    	ObjectOutput output = null;
		try {
			fos = openFileOutput(Constant.FILE_NAME_DATA_STORAGE.getValue() +"-" + this.level.getNum(), Context.MODE_PRIVATE);
			buffer = new BufferedOutputStream(fos);
		    output = new ObjectOutputStream( buffer );
		    output.writeObject(this.imagesGuess);
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		} catch (IOException e) {
			throw new RuntimeException(e);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}finally {
			try {
				output.close();
				buffer.close();
				fos.close();
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
    }
    
    @SuppressWarnings("unchecked")
	private void loadImages(){
    	InputStream fin = null;
		try {
			fin = openFileInput(Constant.FILE_NAME_DATA_STORAGE.getValue() +"-" + this.level.getNum());
			InputStream buffer = new BufferedInputStream(fin);
		    ObjectInput input = new ObjectInputStream( buffer );
		    this.imagesGuess = (LinkedList<Image>)input.readObject();
		} catch (FileNotFoundException e) {
			this.imagesGuess = null;
		} catch (IOException e) {
			e.printStackTrace();
			this.imagesGuess = null;
		} catch (ClassNotFoundException e) {
			throw new RuntimeException(e);
		} finally {
			try {
				if (fin != null){
					fin.close();
				}
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
    }
    
    private void chargeImageToGuess(){
    	if (this.imagesGuess.size() <= this.numberImageToGuess + 1){
    		this.numberImageToGuess = 0;
    	} else{
   			this.numberImageToGuess++;
    	}
    	this.actualImageGuess = this.imagesGuess.get(this.numberImageToGuess);
    	this.startImageAnimation(R.anim.imageappearanimation, actualImageGuess,null);
    	this.chargeLettersImageToGuess();
    }
    
    private void chargeLettersImageToGuess(){
    	RelativeLayout wordLayout = (RelativeLayout)super.findViewById(R.id.wordGuess);
    	String valueToGuess = actualImageGuess.getValueToGuess();
    	//esto lo hacia para mandarles un salto de linea cuando fuesen 3 palabras unicamente o 
    	// cuando sean mas de 3 y las suma de las 2 primeras palabras de 15
    	String cantDePalabras[]= valueToGuess.split(" ");
    	char[] charsToGuess = valueToGuess.toCharArray();
    	Constant text;
    	int marginRight;
    	for (int id = 0; id < charsToGuess.length; id++) {
			Character c = charsToGuess[id];
			if (Character.isSpace(c)){
				text = Constant.SPACE;
				marginRight = 6;
			}else{
				text = Constant.IMAGE_EMPTY;
				marginRight = 3;
			}
			LayoutParams lparams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    		if (id != 0){
    			lparams.addRule(RelativeLayout.RIGHT_OF,id);
    		}
    		TextView letter = this.chargeTextView(wordLayout.getContext(), id+1, lparams, text.getValue());
    		lparams.setMargins(5,5,marginRight,5);//left, top, right, bottom
    		wordLayout.addView(letter);
		}
    }
    
    private TextView chargeTextView(Context context, Integer id, LayoutParams params, String text){
    	
    	TextView letter = new TextView(context);
		letter.setTextAppearance(getApplicationContext(), R.style.textGuessImage);
		letter.setTextColor(Color.BLACK);
		letter.setBackgroundColor(Color.TRANSPARENT);
		letter.setTextSize(20);
		letter.setId(id);
		letter.setText(text);
		letter.setLayoutParams(params);
		return letter;
    	
    }
    
    private void drawImage(){
    	
    	if (this.imagesGuess.size() == 0){
			Toast.makeText(super.getApplicationContext(), "Pasando al nivel siguiente", 2000).show();
    		this.chargeLevel();
    	} else{
    		this.numberOfIntent = 0;
    		this.numberOfLetterGuess = 0;
    		RelativeLayout wordLayout = (RelativeLayout)super.findViewById(R.id.wordGuess);
    		wordLayout.removeAllViewsInLayout();
    		this.chargeImageToGuess();
    		this.chargeLives();
            this.showLevel();
    		this.showScore();
    		if (TypeUse.KEYWORD.equals(this.typeUse)){
    			this.showKeyword(true);
    		}else{
    			TextView letter = (TextView)super.findViewById(R.id.lettersNotGuess);
    			letter.setText("");
    		}
    	}
    }
    
    private void chargeLevel(){
    	this.level = this.level.getNextLevel();
		this.imagesGuess = this.movieBuilder.createImagesByLevel(this.level, this.language, super.getResources(), super.getPackageName());
    	if (this.imagesGuess == null){
			Toast.makeText(super.getApplicationContext(), "No hay mas niveles, y ahora ?", 3000).show();
    	}else{
    		this.saveParameters();
    		this.drawImage();
    	}
    }
    
    public void onClickLetter(View view) {
    	Button button = (Button)view;
    	Boolean guess = this.replaceAllLetter(button.getText().toString());
    	this.checkIfGuess(guess, button);
    }
    
    private Boolean replaceAllLetter(String letterPress){
    	
    	Boolean guess = Boolean.FALSE;
    	String valueToGuess = this.actualImageGuess.getValueToGuess();
		for (int i = 0; i < valueToGuess.length(); i++) {
    		Character a = Character.toLowerCase(letterPress.charAt(0));
    		Character b = Character.toLowerCase(valueToGuess.charAt(i));
    		if (a.equals(b)){
    			RelativeLayout wordLayout = (RelativeLayout)super.findViewById(R.id.wordGuess);
    			View child = wordLayout.getChildAt(i);
    			if (child instanceof TextView){
            		TextView t = (TextView) child;
            		t.setText(letterPress);
            		guess = Boolean.TRUE;
            		this.numberOfLetterGuess++;
            	}
    		}
		}
		return guess;
    }
    
    private AnimationListener buildImageAnimationListener(){
		
    	AnimationListener anim = new Animation.AnimationListener(){
			public void onAnimationEnd(Animation animation) {drawImage();}
			public void onAnimationRepeat(Animation animation) {}
			public void onAnimationStart(Animation animation) {}
    	};
    	
    	return anim;
    	
    }
    
    private void checkIfGuess(boolean guessLetter,Button button){
    	if (guessLetter){ //ADIVINO LA LETRA
    		if (TypeUse.KEYWORD.equals(this.typeUse)){
    			this.hideLetterPress(button);
    		}
    		this.updateScore(Integer.valueOf(Constant.SCORE_WIN_LETTER_GUESS_IMAGE.getValue()));
    		if ((numberOfLetterGuess == this.actualImageGuess.getLengthWithOutSpace())){
    			//ADIVINO LA PALABRA
    			this.actualImageGuess.setWasGuess(true);
    			this.imagesGuess.remove(this.numberImageToGuess.intValue());
    			this.saveImages();
    			this.imagesWereGuess++;
    			Toast.makeText(super.getApplicationContext(), "Adivino", 1000).show();
    			this.startImageAnimation(R.anim.imagedisappearanimation, actualImageGuess,buildImageAnimationListener());
    		}
    	}else{ //NO ACERTO LA LETRA
    		this.decrementLives();
    		this.updateScore(Integer.valueOf(Constant.SCORE_LOSE_LETTER_GUESS_IMAGE.getValue()));
    		if (TypeUse.KEYWORD.equals(this.typeUse)){
    			this.hideLetterPress(button);
    		}
    		Integer value = Integer.valueOf(Constant.MAX_NUMBER_INTENT_TO_GUESS.getValue());
    		if (value <= this.numberOfIntent){
    			//PERDIO LAS VIDAS
    			Toast.makeText(super.getApplicationContext(), "Perdio", 1000).show();
    			this.startImageAnimation(R.anim.imagedisappearanimation, actualImageGuess,buildImageAnimationListener());
    		}
    	}
    }
    
    private void checkIfGuess(boolean guessLetter){
    	this.checkIfGuess(guessLetter,null);
    }
    
    private void hideLetterPress(Button button) {
    	
    	Animation keyAnimation = AnimationUtils.loadAnimation(this, R.anim.keyanimation);
    	button.startAnimation(keyAnimation);
		button.setEnabled(false);
	}
    
    private void showKeyword(boolean enable) {

    	drawLineKeyword((LinearLayout)super.findViewById(R.id.firstLineKeyword),enable);
    	drawLineKeyword((LinearLayout)super.findViewById(R.id.secondLineKeyword),enable);
    	drawLineKeyword((LinearLayout)super.findViewById(R.id.thirdLineKeyword),enable);
	}
    
    private void drawLineKeyword(LinearLayout line, boolean enable){
    	int childCount = line.getChildCount();
    	for (int i = 0; i < childCount; i++) {
			Button button = (Button)line.getChildAt(i);
			button.clearAnimation();
			button.setEnabled(enable);
		}
    	
    }

	private void updateScore(Integer add){
    	this.score+=add;
    	this.saveParameters();
    	this.showScore();
    }
	
	private void showScore(){
		TextView scoreView = (TextView)super.findViewById(R.id.scoreNumber);
		scoreView.setText(this.score.toString());
	}
    
    private void chargeLives(){

    	ImageView intentOne = (ImageView)super.findViewById(R.id.intentOne);
    	intentOne.setImageResource(R.drawable.greenball);
		ImageView intentTwo = (ImageView)super.findViewById(R.id.intentTwo);
		intentTwo.setImageResource(R.drawable.greenball);
		ImageView intentThree = (ImageView)super.findViewById(R.id.intentThree);
		intentThree.setImageResource(R.drawable.greenball);
    }
    
    private void startImageAnimation(int resourceAnimation, Image actualImageGuess, AnimationListener listener){
    	if (TypeUse.KEYWORD.equals(this.typeUse)){
    		this.showKeyword(false);
    	}
    	ImageView guessImage =(ImageView)super.findViewById(R.id.guessImage);
    	guessImage.setImageResource(actualImageGuess.getIdentifierResource());
    	Animation imageAnimation = AnimationUtils.loadAnimation(this, resourceAnimation);
    	imageAnimation.setAnimationListener(listener);
    	guessImage.setAnimation(imageAnimation);
    }
    
    private void decrementLives(){
    	this.numberOfIntent++;
    	switch (this.numberOfIntent) {
    		case 1:{
    			ImageView intent = (ImageView)super.findViewById(R.id.intentOne);
    			intent.setImageResource(R.drawable.redball);
    			break;
    		}
    		case 2:{
    			ImageView intent = (ImageView)super.findViewById(R.id.intentTwo);
    			intent.setImageResource(R.drawable.redball);
    			break;
    		}
    		default:{
    			ImageView intent = (ImageView)super.findViewById(R.id.intentThree);
    			intent.setImageResource(R.drawable.redball);
    			break;
    		}
		}
    }

    public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
		ArrayList<Prediction> predictions = mLibrary.recognize(gesture);
		if (predictions.size() > 0) {
			if (predictions.get(0).score > 1.0) {
				String letter = predictions.get(0).name;
				Boolean guess = this.replaceAllLetter(letter);
				if (!guess && !wasLetter(letter)){
					this.showLetterNotGuess(letter);
				}
				this.checkIfGuess(guess);
			}
		}
	}
    
    private void showLetterNotGuess(String letter) {
    	
    	TextView letterView = (TextView)super.findViewById(R.id.lettersNotGuess);
    	String text = String.valueOf(letterView.getText());
    	text = text + letter + "-";
    	letterView.setText(text.toUpperCase());
    }
    
    private Boolean wasLetter(String letter) {
    	
    	TextView letterView = (TextView)super.findViewById(R.id.lettersNotGuess);
    	String text = String.valueOf(letterView.getText());
    	return text.toLowerCase().contains(letter.toLowerCase());
    }
}